home *** CD-ROM | disk | FTP | other *** search
- /*
- * Signal handling nonsense. Signals need to be dealt with in their
- * own class. Suggestions anyone?
- *
- * Main chore here is to catch all nasty signals in the parent so we can kill
- * off all the children processes so they don't loop forever. (if the parent
- * dies while "busy", he never gets unbusy) We can't protect against
- * noncatchable signals in the parent, specificall SIGKILL. The best we can do
- * is in the children, check every once in a while if the current ppid is not
- * init. Really need a SIGPARENT (SIGPARNT?) to notify the children that its
- * parent has changed.
- *
- * Last modified:
- * bnb
- * 1/27/88 to create
- */
-
-
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <osfcn.h>
- #include "presto.h"
-
-
- //
- // Route all normal default signals through the parent handler. Children
- // should not be handling signals other than those WHICH are defined
- // by presto. The whole idea of signals in this environment is strange.
- // Signals are for processes. Signals should be for threads.
- //
-
-
- typedef int (*PFSigHandler)(int, int, sigcontext*);
- int schedulerSigHandler(int sig, int code, struct sigcontext *scp);
- int schedulerReapChild(int sig, int code, struct sigcontext *scp);
-
- #ifdef sequent
- static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),1};
- static struct sigvec CHLD_vec = {schedulerReapChild, 0, 1};
- #endif sequent
- #ifdef sun
- static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
- static struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
- #endif sun
- #ifdef vax
- static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
- static struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
- #endif vax
-
- // default handler
- static struct sigvec DFL_vec = {(PFSigHandler)SIG_DFL, 0, 0};
-
- #ifdef sequent // force kernel sigvec to be called
- #define SIGVEC_OS _sigvec
- #endif sequent
-
- #ifdef sun
- #define SIGVEC_OS sigvec
- #endif sun
-
- #ifdef vax
- #define SIGVEC_OS sigvec
- #endif vax
-
- extern int SIGVEC_OS(int, struct sigvec*, struct sigvec*);
-
- //
- // Force the parent to come through here on all signals that
- // are "unpleasant" and not already handled.
- //
- void
- Scheduler::initsighandlers(int setupdefaults)
- {
- struct sigvec sv;
- int sig;
-
- if (setupdefaults == 0) {
- SIGVEC_OS(SIGCHLD, &CHLD_vec, (struct sigvec*)0);
- return;
- } else if (setupdefaults < 0) {
- /*
- * Don't be bothered by exiting children.
- */
- SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);
- return;
- }
-
- for (sig = 1; sig < NSIG; sig++) {
- switch (sig) {
- case SIGSTOP:
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- case SIGURG:
- case SIGCONT:
- case SIGIO:
- case SIGCHLD:
- case SIGWINCH:
- continue;
- default:
- if (SIGVEC_OS(sig, 0, &sv) < 0)
- continue; // might make some noise
- if (sv.sv_handler != (PFSigHandler)SIG_DFL)
- continue;
- (void) SIGVEC_OS(sig, &HAND_vec, (struct sigvec *)0);
- }
- }
- }
-
- //
- // Parent proc comes here when it is time to kill everyone off.
- // We do not necessarily get a core dump and we do not terminate
- // ourselves. The caller must do that. We just kill off everybody else.
- //
- // if sig is negative, then we are not the parent, but a child proc
- // who says KILL EVERYONE and forgewt about being polite. Child procs
- // should use this when they detect that their parent is dead, but
- // realize that everyone else must die also. If the root proc does this,
- // nobody will be cleaned up after, but it would still work.
- //
- // Killer siblings can end up killing one another more than they need
- // too, since we don't bother to mark thisproc as reaped before it
- // nukes itself. It doesn't matter, in the worst case, some guys get killed
- // more than once.
- //
- void
- Scheduler::abort(int sig)
- {
- int pnum; // proc num of dying proc
- int tpid; // pid of dying proc
- union wait status; // and how they died
- int waitforchild = 1; // presume we are parent
-
- if (sig < 0) {
- sig = -sig;
- waitforchild = 0;
- } else {
- if (thisproc != sc_p_procs[0]) { // non root proc
- kill(thisproc->pid(), sig); // just dies, parent
- } // should clean up
- //
- // only root process gets this far
- //
- // no interruptions please
- SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);
- }
- for (pnum = 0; pnum < sc_p_numschedulers; pnum++) {
- Process *p = sc_p_procs[pnum];
-
- if (p == thisproc) // we've got a JOB to do!
- continue;
-
- if (waitforchild && p->state()&S_REAPED)// not sibling killer
- continue; // and already reaped
-
- //
- // Could either pass sig along to all children, in which
- // case we might end up with tons of core files, or
- // just say "to hell with it", one core file is enough.
- // All we care about here is that everybody else stops
- //
-
- while (kill( p->pid(), SIGKILL) == 0)
- continue; // force him to die
-
- if (waitforchild == 0) // can't reap sibling
- continue;
-
- //
- // pick up dead procs. Deal with the chance that
- // multiple guys may die while we are doing this
- //
- do {
- tpid = wait((int*)(&status));
- if (tpid >= 0) {
- int procnum = pidtoprocnum(tpid);
- if (procnum >= 0)
- sc_p_procs[procnum]->setstate(S_REAPED);
- if (status.w_coredump)
- storecore(pidtoprocnum(tpid));
- }
- } while (tpid != p->pid() && tpid >= 0);
- }
- //
- // You may see this message more than once. Can't lock though
- // cuz we could get killed in the lock, and then nobody else
- // could proceed.
- //
- if (waitforchild == 0)
- cerr << "Sibling ";
- cerr << "Scheduler aborting with signal " << sig << "\n";
- (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
- (void)kill(thisproc->pid(), sig);
- // NOT REACHED (definitely)
- }
-
- //
- // Write a core file. Hope we get to move it before someone else
- // dumps. The first core file that dumps is called simply "core.First",
- // all the rest are appended with the number of the processor
- // that dumped.
- // If you end up with a core.-1 file, then something bizarre happened to the
- // pid to procnum mapping function and you may be missing some core files.
- // As they say in te compouter business "This should never happen."
- //
-
- void
- Scheduler::storecore(int pnum)
- {
- int rename(char*, char*);
- static int firstdump = 1;
- char cname[16];
-
- if (firstdump) {
- sprintf(cname,"core.First");
- firstdump = 0;
- } else {
- sprintf(cname,"core.%d", pnum);
- }
- cerr << "Caught core file " << (char*)&cname[0] << "\n";
- (void)rename("core", cname);
- }
-
- int
- Scheduler::pidtoprocnum(int pid)
- {
- int p;
- for (p = 0; p < sc_p_numschedulers; p++)
- if (pid == sc_p_procs[p]->pid())
- return p; // presto pid
- return -1;
- }
-
-
- //
- // SIGCHLD handler. If we are the root proc, clean up the child, abort
- // everyone else with the a clean signal. We never return from
- // schedulerSigHandler
- // unless we are already handloing some kind of a terminating signal.
- //
- int
- schedulerReapChild(int sig, int code, struct sigcontext *scp)
- {
- union wait status;
- int tpid;
- int procnum;
- int wait3(union wait*, int, int);
-
- if (sched == 0)
- return 0; //???
- if (thisproc != sched->sc_p_procs[0])
- return 0; // who else and why would would it be caught?
-
- tpid = wait3(&status, WNOHANG|WUNTRACED, 0);
-
- if (tpid <= 0)
- return 0 ; // spurious?
- if (WIFSTOPPED(status)) // child could pause
- return 0;
-
- cerr << "Process " << tpid ;
- if (WIFSIGNALED(status)) {
- procnum = sched->pidtoprocnum(tpid);
- if (procnum >= 0)
- sched->sc_p_procs[procnum]->setstate(S_REAPED);
-
- if (status.w_coredump)
- sched->storecore(procnum);
- cerr << " killed " << status.w_termsig << "\n";
- } else // must have just exited
- cerr << " exited " << status.w_termsig << "\n";
- //
- // don't bother to core dump everyone else
- //
- schedulerSigHandler(SIGKILL, code, scp);
- //
- // NOT REACHED (well... maybe)
- //
- sig=sig;
- return 0;
- }
-
- //
- //
- // parent comes here when we get a "default" signal
- //
- int
- schedulerSigHandler(int sig, int code, struct sigcontext *scp)
- {
- static int aborting = 0; // avoid looping on signals
- if (sched) { // once the axe is in motion
- if (aborting == 0) {
- aborting++;
- sched->abort(sig);
- // NOT REACHED
- } else
- return 0;
- } else {
- // sig ourselves
- (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
- (void)kill(getpid(), sig);
- // NOT REACHED
- }
- code=code;scp=scp;
- return 0;
- }
-